<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>1.用webgl绘制3D物体-绘制三维立方体</title>
    <style>
        canvas{
            border:1px solid #aaa;
            margin: 0 auto;
            display: block;
        }
    </style>
</head>
<body>
    <canvas width="554" height="554"></canvas>
    <script src="/common/lib/gl-renderer.js"></script>

    <script type="module">
        import { loadImage, toPolar, fromPolar } from "/common/lib/utils.js";
        import {Animator} from '/common/lib/animator.js';
        import {multiply} from '/common/lib/math/functions/Mat4Func.js';

        // 用立方体沿 x、y、z 轴的旋转来生成模型矩阵
        function fromRotation(rotationX, rotationY, rotationZ) {
            let c = Math.cos(rotationX);
            let s = Math.sin(rotationX);
            const rx = [
                1, 0, 0, 0,
                0, c, s, 0,
                0, -s, c, 0,
                0, 0, 0, 1,
            ];

            c = Math.cos(rotationY);
            s = Math.sin(rotationY);
            const ry = [
                c, 0, s, 0,
                0, 1, 0, 0,
                -s, 0, c, 0,
                0, 0, 0, 1,
            ];

            c = Math.cos(rotationZ);
            s = Math.sin(rotationZ);
            const rz = [
                c, s, 0, 0,
                -s, c, 0, 0,
                0, 0, 1, 0,
                0, 0, 0, 1,
            ];

            const ret = [];
            multiply(ret, rx, ry);
            multiply(ret, ret, rz);
            return ret;
        }
        // 生成立方体的24个顶点信息，6个面的颜色信息，12个三角形索引
        function cube(size = 1.0, colors = [[1, 0, 0, 1]]){
            // 立方体边长
            const h = 0.5 * size;
            // 8个顶点信息
            const vertices = [
                [-h, -h, -h],
                [-h, h, -h],
                [h, h, -h],
                [h, -h, -h],
                [-h, -h, h],
                [-h, h, h],
                [h, h, h],
                [h, -h, h],
            ];
            
            const positions = [];
            const color = [];
            const cells = [];

            let colorIdx = 0;
            let cellsIdx = 0;
            const colorLen = colors.length;

            function quad(a, b, c, d){
                [a, b, c, d].forEach(i => {
                    // 6个面 24个顶点
                    positions.push(vertices[i]);
                    // 每个顶点设置颜色值
                    color.push(colors[colorIdx % colorLen]);
                });
                // 每个面被三角剖分成两个三角形
                cells.push(
                    [0, 1, 2].map(i => i + cellsIdx),
                    [0, 2, 3].map(i => i + cellsIdx),
                );
                colorIdx++;
                cellsIdx += 4;
            }

            // 立方体的6个面分别处理
            quad(1, 0, 3, 2); 
            quad(4, 5, 6, 7); 
            quad(2, 3, 7, 6); 
            quad(5, 4, 0, 1); 
            quad(3, 0, 4, 7); 
            quad(6, 5, 1, 2); 

            return {positions, color, cells};
        }

        /**
         * gl-renderer五步法
         * 1.创建renderer对象
         * 2.创建并启用webgl程序
         * 3.设置uniform变量
         * 4.将定点数据送入缓冲区
         * 5.渲染
         * 
        */
        // 1.
        let canvas = document.querySelector("canvas");
        const renderer = new GlRenderer(canvas, {  depth: true });

        // 2.
        const vertex = `
            attribute vec3 a_vertexPosition;
            attribute vec4 color;

            varying vec4 vColor;
            // 投影矩阵
            uniform mat4 projectionMatrix;
            // 模型矩阵
            uniform mat4 modelMatrix;

            void main(){
                gl_PointSize = 1.0;
                vColor = color;
                gl_Position = projectionMatrix * modelMatrix * vec4(a_vertexPosition, 1.0);
            }
        `
        // 
        const fragment = `
        #ifdef GL_ES
            precision highp float;
            #endif

            varying vec4 vColor;

            void main() {
                vec4 color = vColor;
                gl_FragColor = color;
            }
        `
        const program = renderer.compileSync(fragment, vertex);
        renderer.useProgram(program);

        
        const geometry = cube(1.0, [
            [1, 0, 0, 1],
            [0, 0.5, 0, 1],
            [0, 0, 1, 1],
        ]);

        // webgl实际坐标是左手系（右手系是使用习惯），所以需要用齐次矩阵，将左手系转换右手系，这个矩阵也叫投影矩阵
        renderer.uniforms.projectionMatrix = [
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, -1, 0,
            0, 0, 0, 1
        ]
        // 模型矩阵，作用于要变换的物体
        renderer.uniforms.modelMatrix = fromRotation(0, 0, 0);
        
        
        // 顶点信息
        renderer.setMeshData([{
            positions: geometry.positions,
            attributes: {
                color: geometry.color,
            },
            cells: geometry.cells,
        }]);
        renderer.render();


        // 旋转的立方体
        let rotateX = 0, rotateY = 0, rotateZ = 0;

        function update(){
            rotateX += 0.003;
            rotateY += 0.005;
            rotateZ += 0.007;
            renderer.uniforms.modelMatrix = fromRotation(rotateX, rotateY, rotateZ);
            requestAnimationFrame(update)
        }
        update()
    </script>
</body>
</html>